package br.com.ro.model.dao.util.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Criterion;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import br.com.ro.model.dao.util.GenericDao;

public class GenericDaoImpl<T, ID extends Serializable> extends HibernateDaoSupport implements GenericDao<T, ID> {

	private static Log LOG = LogFactory.getLog(GenericDaoImpl.class);

	@SuppressWarnings("unchecked")
	public GenericDaoImpl() {
		this.persistentClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
	}

	private Class<T> persistentClass;

	public Class<T> getPersistentClass() {
		return this.persistentClass;
	}

	@Override
	public void delete(T entity) {
		try {
			this.getHibernateTemplate().delete(entity);
		} catch (final HibernateException ex) {
			GenericDaoImpl.LOG.error(ex);
			throw convertHibernateAccessException(ex);
		}
	}

	@Override
	public T findById(ID id) {
		try {
			return (T) this.getHibernateTemplate().get(getPersistentClass(), id);
		} catch (final HibernateException ex) {
			GenericDaoImpl.LOG.error(ex);
			throw convertHibernateAccessException(ex);
		}
	}

	@Override
	public List<T> listAll() {
		try {
			return this.getHibernateTemplate().loadAll(getPersistentClass());
		} catch (final HibernateException ex) {
			GenericDaoImpl.LOG.error(ex);
			throw convertHibernateAccessException(ex);
		}
	}

	@Override
	public T save(T entity) {
		try {
			this.getHibernateTemplate().saveOrUpdate(entity);
			return entity;
		} catch (final HibernateException ex) {
			GenericDaoImpl.LOG.error(ex);
			throw convertHibernateAccessException(ex);
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> findByCriteria(Criterion... criterion) {
		Session session = null;
		try {
			session = this.getHibernateTemplate().getSessionFactory().openSession();
			Criteria crit = session.createCriteria(getPersistentClass());
			for (Criterion c : criterion) {
				crit.add(c);
			}
			return crit.list();
		} catch (final HibernateException ex) {
			GenericDaoImpl.LOG.error(ex);
			throw convertHibernateAccessException(ex);
		} finally {
			session.close();
		}
	}

	@SuppressWarnings("unchecked")
	public List<T> findBySQL(String sql) {
		Session session = null;
		try {
			session = this.getHibernateTemplate().getSessionFactory().openSession();
			Query q = session.createQuery(sql);
			return q.list();
		} catch (final HibernateException ex) {
			GenericDaoImpl.LOG.error(ex);
			throw convertHibernateAccessException(ex);
		} finally {
			session.close();
		}
	}
}
